home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1993-94, Silicon Graphics, Inc.
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the name of Silicon Graphics may not be used in any advertising or
- * publicity relating to the software without the specific, prior written
- * permission of Silicon Graphics.
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
- * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
- * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
- */
- /*
- * bufferogl: an openGL-Xlib version of Yusuf Attarwala's Motif-based 4.0
- * mixed model "bufferglm.c" demo program. This is the "after"
- * version, ported from its "before" counterpart, located at
- * ../../GLX/buffer/bufferglx.c
- *
- * bufferogl implements an openGL methodology for creating and
- * then switching back-and-forth between single and double
- * -buffer visuals or drawing modes.
- *
- * left mouse : switch to single buffer
- * middle mouse: switch to double buffer
- * right mouse : animate the green sphere in the current buffer mode
- * ESC key : exits the program
- *
- * the program handles redraw (ConfigureNotify--move and resize) and
- * expose (pop, expose, de-iconify) and button (i.e. mouse) events.
- * ratmandu -- ported July, 1993
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <GL/glx.h>
- #include <GL/gl.h>
- #include <GL/glu.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/keysym.h>
-
- #define top 0 /* parent X window array index */
- #define SBglwin 1 /* singlebuffer'd RGBA GL window index */
- #define DBglwin 2 /* doublebuffer'd RGBA GL window index */
- #define WINMAX 3 /* number of unique windows */
-
- #define Mat1 1 /* we'll use two material definitions, */
- #define Mat2 2 /* for lighting, one for each sphere */
-
- static void openwindow(char *);
- void Winset(int);
- static void resize_buffer(long);
- static void clean_exit(void);
- void initGL(void);
- void setMatrix(void);
- void loop(void);
- void drawScene(void);
-
- Display *dpy; /* The X server connection */
- Atom del_atom; /* for possibility of WM killing app */
- Window glwins[WINMAX]; /* array for SB/DB window ids */
- GLXContext glcontexts[WINMAX]; /* array for SB/DB window context ids */
- float ax, ay, az; /* angles green sphere twirls on */
- int xsize, ysize; /* current size-of-window keepers */
- long buffermode; /* flag for cur win (single||double) */
- XEvent event; /* needs to be global for XIfEvent */
- GLUquadricObj *quadObj; /* used to make the two spheres with */
-
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- KeySym keysym; /* for catching */
- char buf[4]; /* keyboard events */
- int myExpose, myConfigure,
- myButtRelease, myKeyPress; /* store which events occur */
-
-
- myExpose = myConfigure = myButtRelease = myKeyPress = GL_FALSE;
-
- openwindow(argv[0]);
-
- /* initialize *both* windows just as we wud do with winopen/winset */
- Winset(DBglwin);
- initGL(); /* do GL init stuff */
- setMatrix();
-
- /* start out making the singlebuffer window be our current GL window */
- Winset(SBglwin);
- initGL(); /* do GL init stuff */
- setMatrix();
- drawScene(); /* and begin by drawing the scene in singlebuffer mode */
-
-
- /*
- * The event loop.
- */
- while (1) { /* standard logic: get event(s), process event(s) */
-
- glFlush(); /* For proper DGL performance */
-
- /* this "do while" loop does the `get events' half of the "get events,
- * process events" action of the infinite while. this is to ensure
- * the event queue is always drained before the events that have come
- * in are processed.
- */
- do {
-
- XNextEvent(dpy, &event);
- switch (event.type) {
-
- /* "Expose" events are sort of like "REDRAW" in gl-speak in
- * terms of when a window becomes visible, or a previously
- * invisible part becomes visible.
- */
- case Expose: /* Exposures */
- myExpose = GL_TRUE;
- break;
-
-
- /* "ConfigNotify" events are like "REDRAW" in terms of changes
- * to a window's size or position.
- */
- case ConfigureNotify: /* Resize GL manually */
- if (event.xconfigure.window == glwins[top]) {
- /* save the changed width/height of the parent X window */
- xsize = event.xconfigure.width;
- ysize = event.xconfigure.height;
- myConfigure = GL_TRUE;
- }
- break;
-
-
- /* Wait for "ButtonRelease" events so the queue doesn't fill up
- * the way it wud if the user sits on ButtonPresss.
- */
- case ButtonRelease:
- if (event.xbutton.button == Button1) { /* LEFTMOUSE: */
- buffermode = SBglwin; /* switch to */
- myButtRelease = GL_TRUE; /* singlebuffer*/
- } else if (event.xbutton.button == Button2) {
- buffermode = DBglwin; /* MIDDLEMOUSE: switch */
- myButtRelease = GL_TRUE; /* to doublebuffer mode */
- } else if (event.xbutton.button == Button3) {
- loop(); /* RIGHTMOUSE: */
- } /* twirl green sphere */
- break;
-
-
- /* "ClientMessage" is generated if the WM itself is being
- * gunned down and sends an exit signal to any running prog.
- */
- case ClientMessage:
- if (event.xclient.data.l[0] == del_atom)
- clean_exit();
- break;
-
-
- /* "KeyPress" events are those that would be generated before
- * whenever queueing up any KEYBD key via qdevice.
- */
- case KeyPress:
- /* save out which unmodified key (i.e. the key was
- * not modified w/something like "Shift", "Ctrl",
- * or "Alt") got pressed for use below.
- */
- XLookupString((XKeyEvent *)&event, buf, 4, &keysym, 0);
- myKeyPress = GL_TRUE;
- break;
-
- } /* end switch (event.type) */
-
-
- } while (XPending(dpy)); /* end "do { } while".
- * XPending() is like qtest()--it only
- * tells you if there're any events
- * presently in the queue. it does not
- * disturb queue's contents in any way.
- */
-
- /* On an "Expose" event, redraw the affected pop'd or de-iconized window
- */
- if (myExpose) {
- drawScene(); /* draw the GL stuff */
- myExpose = GL_FALSE; /* reset flag--queue now empty */
- }
-
- /* On a "ConfigureNotify" event, the GL window has either been moved or
- * resized. Respond accordingly and then redraw its contents.
- */
- if (myConfigure) {
- if (buffermode == SBglwin) {
- resize_buffer(DBglwin); /* update viewport & CTM stuff */
- resize_buffer(SBglwin); /* for *both* windows and then */
- } else if (buffermode == DBglwin) {
- resize_buffer(SBglwin);
- resize_buffer(DBglwin);
- }
- drawScene();
- myConfigure = GL_FALSE; /* reset flag--queue now empty */
- }
-
- /* On a "ButtonRelease" event, the flag gets set only for the LEFTMORE
- * or MIDDLEMOUSE. we need to change the buffermode state in this case.
- * In either case, XStoreName updates the window's title bar, Winset
- * then switches to the current buffermode graphics context, and we
- * Map the current window *BEFORE* we unmap the previous one. this
- * alleviates a painful "flicker" that occurs if you unmap the previous
- * window first.
- */
- if (myButtRelease) {
- if (buffermode == SBglwin) {
- XStoreName(dpy,glwins[top],
- "single[LEFTMOUSE]-buffer GL window");
- XRaiseWindow(dpy, glwins[SBglwin]);
- Winset(SBglwin);
- } else if (buffermode == DBglwin) {
- XStoreName(dpy,glwins[top],
- "double[RIGHTMOUSE]-buffer GL window");
- XRaiseWindow(dpy, glwins[DBglwin]);
- Winset(DBglwin);
- }
- myButtRelease = GL_FALSE;
- }
-
- /* On a keypress of Esc key, exit program.
- */
- if (myKeyPress) {
- if (keysym == XK_Escape)
- clean_exit();
- }
-
- } /* end while(1) */
-
- } /* end main */
-
-
-
- static int SBattributeList[] = { GLX_RGBA,
- GLX_DEPTH_SIZE, 1,
- None };
- static int DBattributeList[] = { GLX_RGBA,
- GLX_DOUBLEBUFFER,
- GLX_DEPTH_SIZE, 1,
- None };
-
- /* WaitForNotify:
- * used to make sure the MapWindow() calls inside openwindow() occur
- * beFORE glXMakeCurrent() is invoked so as to avoid a race condition.
- */
- static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
- return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
- }
-
-
- /* openwindow -
- * establish connection to X server, get screen info, specify the
- * attributes we want the WM to try to provide, and create the 2
- * GL windows--one single and one double -buffered--that we'll employ.
- */
- static void openwindow(char *progname) {
-
- XSizeHints Winhints; /* used to fix window size */
- XSetWindowAttributes SBswa, DBswa;
- XColor gray;
- XVisualInfo *SBvi, *DBvi;
- Colormap SBcmap, DBcmap;
- int scrnnum; /* X screen number */
- int xorig, yorig;
- long scrnheight; /* for defining maximum resize*/
-
-
-
- /* Connect to the X server and get screen info */
- if ((dpy = XOpenDisplay(NULL)) == NULL) {
- fprintf(stderr, "%s: cannot connect to X server %s\n",
- progname, XDisplayName(NULL));
- exit(1);
- }
- scrnnum = DefaultScreen(dpy);
- scrnheight = DisplayHeight(dpy, scrnnum);
-
- xorig = 0; yorig = 0; /* define window initial size */
- xsize = 300; ysize = 300;
-
- /* first create the top level X window which will be the parent to both
- * the singlebuffer and doublebuffer rendering windows
- */
- glwins[top] = XCreateSimpleWindow(dpy, RootWindow(dpy, scrnnum),
- xorig, yorig, xsize, ysize, 0, 0, 0);
- if (!(glwins[top])) {
- fprintf(stderr,"%s: couldn't create \"parent\" X window\n",progname);
- exit(1);
- }
- /* including this call to XSelectInput shud not be necessary, but there's
- * a bug, so we have to resort to this hackaround.
- */
- XSelectInput(dpy, glwins[top],
- StructureNotifyMask|ButtonPressMask|ButtonReleaseMask|KeyPressMask);
-
- /* define the string that will show up in the window title bar (and icon) */
- XStoreName(dpy,glwins[top],"single/double -buffer program");
-
- /* specify the values for the Window Size Hints we want to enforce: this
- * window's aspect ratio needs to stay at 1:1, constrain min and max
- * window size, and specify the initial size of the window.
- */
- Winhints.width = xsize; /* specify desired x/y size of window */
- Winhints.height = ysize;
- Winhints.min_width = xsize; /* define min and max */
- Winhints.max_width = scrnheight-1; /* width and height */
- Winhints.min_height = ysize;
- Winhints.max_height = scrnheight-1;
- Winhints.min_aspect.x = 1; /* keep aspect at a 1:1 ratio */
- Winhints.max_aspect.x = 1;
- Winhints.min_aspect.y = 1;
- Winhints.max_aspect.y = 1;
- /* set the corresponding flags */
- Winhints.flags = USSize|PMaxSize|PMinSize|PAspect;
- XSetNormalHints(dpy, glwins[top], &Winhints);
-
-
- /* now define and create the single and doublebuffer rendering windows */
-
- /* first get the appropriate visuals */
- SBvi = glXChooseVisual(dpy, scrnnum, SBattributeList);
- DBvi = glXChooseVisual(dpy, scrnnum, DBattributeList);
-
- /* create the appropriate GLX contexts */
- glcontexts[SBglwin] = glXCreateContext(dpy, SBvi, 0, GL_TRUE);
- glcontexts[DBglwin] = glXCreateContext(dpy, DBvi, 0, GL_TRUE);
-
- /* now create the two colormaps */
- SBcmap = XCreateColormap(dpy, RootWindow(dpy, SBvi->screen),
- SBvi->visual, AllocNone);
- DBcmap = XCreateColormap(dpy, RootWindow(dpy, DBvi->screen),
- DBvi->visual, AllocNone);
-
- /* now create both windows */
- SBswa.colormap = SBcmap;
- SBswa.border_pixel = 0;
- SBswa.event_mask = StructureNotifyMask | ButtonReleaseMask |
- ButtonPressMask | KeyPressMask; /* express interest in events */
- glwins[SBglwin] = XCreateWindow(dpy, glwins[top],
- xorig, yorig, xsize, ysize,
- 0, SBvi->depth, InputOutput, SBvi->visual,
- CWBorderPixel|CWColormap|CWEventMask, &SBswa);
- DBswa.colormap = DBcmap;
- DBswa.border_pixel = 0;
- DBswa.event_mask = StructureNotifyMask | ButtonReleaseMask |
- ButtonPressMask | KeyPressMask; /* express interest in events */
- glwins[DBglwin] = XCreateWindow(dpy, glwins[top],
- xorig, yorig, xsize, ysize,
- 0, DBvi->depth, InputOutput, DBvi->visual,
- CWBorderPixel|CWColormap|CWEventMask, &DBswa);
-
- /* now map both windows, but leave the singlebuffer window on top */
- XMapWindow(dpy, glwins[SBglwin]);
- XMapWindow(dpy, glwins[DBglwin]);
- XIfEvent(dpy, &event, WaitForNotify, (char*)glwins[DBglwin]);
- XRaiseWindow(dpy, glwins[SBglwin]);
- XIfEvent(dpy, &event, WaitForNotify, (char*)glwins[SBglwin]);
- XMapWindow(dpy, glwins[top]);
-
- /* connect the context to the window */
- glXMakeCurrent(dpy, glwins[SBglwin], glcontexts[SBglwin]);
-
- /* ensure the GL colormap is installed for this app */
- XSetWMColormapWindows(dpy, glwins[top], glwins, WINMAX);
-
- /* express interest in WM being able to kill this app */
- if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", True)) != None)
- XSetWMProtocols(dpy, glwins[top], &del_atom, 1);
-
- glFlush();
- }
-
-
- char *typeToName[] = {
- "parent window",
- "RGB single buffer",
- "RGB double buffer",
- };
-
-
- /* A little helper wrapper for glXMakeCurrent.
- * passes the index to jointly access the windows and contexts array and
- * checks the return value. This makes the call to begin GL drawing a
- * little simpler. Building in such automatic error checking is always a
- * "smooth move" (*not* like the cancerously-mutant human with the enlarged
- * proboscis plastered all over the place urging people to be likewise
- * smoothly cancerous and hardly cool).
- */
- void Winset(int type)
- {
- int rv;
-
- /*
- XIfEvent(dpy, &event, WaitForNotify, (char*)glwins[type]);
- */
- XSync(dpy,GL_FALSE);
- rv = glXMakeCurrent(dpy, glwins[type], glcontexts[type]);
- if (rv == GL_FALSE) {
- fprintf(stderr, "glXMakeCurrent failed for an %s-type window\n",
- typeToName[type]);
- exit(-1);
- }
- }
-
-
- /* window has been moved or resized so update viewport & CTM stuff.
- */
- static void resize_buffer(long wintype) {
-
- Winset(wintype);
- XMoveResizeWindow(dpy, glwins[wintype], 0, 0, xsize, ysize);
- glViewport(0, 0, xsize-1, ysize-1);
- }
-
-
-
- /* clean up before exiting
- */
- static void clean_exit(void)
- {
- XCloseDisplay(dpy);
- exit(0);
- }
-
-
- /* setup all necessary GL initialzation parameters.
- * do our materials/lighting definitions, enable what we need, and define
- * the properites with gluQuadric for our two sphere objects.
- */
- void
- initGL()
- {
- GLfloat mat1_diff[] = { 0.6, 0.2, 0.2, 1.0 };
- GLfloat mat1_spec[] = { 1.0, 1.0, 1.0, 1.0 };
- GLfloat mat1_shin[] = { 120.0 };
-
- GLfloat mat2_diff[] = { 0.2, 0.8, 0.2, 1.0 };
- GLfloat mat2_spec[] = { 1.0, 1.0, 1.0, 1.0 };
- GLfloat mat2_shin[] = { 120.0 };
-
- GLfloat light_ambi[] = { 0.2, 0.2, 0.2, 1.0 };
- GLfloat light_diff[] = { 0.9, 0.9, 0.9, 1.0 }; /* diffuse & specular */
- GLfloat light_spec[] = { 0.9, 0.9, 0.9, 1.0 }; /* are now equivalent */
- GLfloat light_posi[] = { 10.0, 50.0, 50.0, 0.0 }; /* to the old LCOLOR */
-
- GLfloat liteModel_ambient[] = { 0.3, 0.3, 0.3, 1.0 };
-
- glNewList(Mat1, GL_COMPILE);
- glMaterialfv(GL_FRONT, GL_DIFFUSE, mat1_diff);
- glMaterialfv(GL_FRONT, GL_SPECULAR, mat1_spec);
- glMaterialfv(GL_FRONT, GL_SHININESS, mat1_shin);
- glEndList();
-
- glNewList(Mat2, GL_COMPILE);
- glMaterialfv(GL_FRONT, GL_DIFFUSE, mat2_diff);
- glMaterialfv(GL_FRONT, GL_SPECULAR, mat2_spec);
- glMaterialfv(GL_FRONT, GL_SHININESS, mat2_shin);
- glEndList();
-
- glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambi);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diff);
- glLightfv(GL_LIGHT0, GL_SPECULAR, light_spec);
- glLightfv(GL_LIGHT0, GL_POSITION, light_posi);
- glLightModelfv (GL_LIGHT_MODEL_AMBIENT, liteModel_ambient);
-
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glEnable(GL_DEPTH_TEST);
-
- quadObj = gluNewQuadric(); /* used to define the two spheres */
- gluQuadricDrawStyle(quadObj,GLU_FILL); /* draw the spheres as polygons */
- gluQuadricNormals(quadObj, GLU_SMOOTH); /* make the spheres smooth */
- gluQuadricOrientation(quadObj,GLU_OUTSIDE); /* draw w/nrmls pnting out */
-
- buffermode = SBglwin; /* start out in singlebuffer mode */
- }
-
-
- /* define our Current Transformation Matrix
- */
- void
- setMatrix()
- {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(-10.0, 10.0, -10.0*ysize/xsize, 10.0*ysize/xsize, -10.0, 10.0);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- gluLookAt(0.0, 0.0, 4.0, 0.0, -1.5, 0.0, 0.0, 1.0, 0.0);
- }
-
-
-
- /* draw our two spheres
- */
- void
- drawScene()
- {
- glClearColor(0.3, 0.3, 0.3, 0.0);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
- glPushMatrix();
- glPushMatrix();
- glCallList(Mat1);
- glTranslatef(0.2, 0.2, 0.2);
- gluSphere(quadObj, 3.0, 20, 20);
- glPopMatrix();
- glRotatef(-ax, 1.0, 0.0, 0.0);
- glRotatef(ay, 0.0, 1.0, 0.0);
- glRotatef(az, 0.0, 0.0, 1.0);
- glTranslatef(3.4, 3.4, 0.2);
- glCallList(Mat2);
- gluSphere(quadObj, 4.0, 20, 20);
- glPopMatrix();
-
- if (buffermode == DBglwin)
- glXSwapBuffers(dpy, glwins[DBglwin]);
-
- glFlush();
- }
-
-
- /* perform one loop of twirling the green sphere
- */
- void
- loop()
- {
- register int i;
-
- for (i=0;i<50;i++) {
- ax += 5.0;
- ay -= 2.0;
- az += 5.0;
- if (ax >= 360.0) ax = 0.0;
- if (ay <= -360.0) ay = 0.0;
- if (az >= 360.0) az = 0.0;
- drawScene();
- }
- }
-